package com.captjack.micro.configcenter.configuration;

import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.cloud.bus.ConditionalOnBusEnabled;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * rabbitmq 消息队列配置
 *
 * @author Capt Jack
 * @date 2018/4/19
 */
@Configuration
@ConditionalOnBusEnabled
public class RabbitMessageQueueConfiguration {

    /**
     * 1.定义direct exchange，绑定queueTest
     * 2.durable="true" rabbitmq重启的时候不需要创建新的交换机
     * 3.direct交换器相对来说比较简单，匹配规则为：如果路由键匹配，消息就被投送到相关的队列
     * fanout交换器中没有路由键的概念，他会把消息发送到所有绑定在此交换器上面的队列中。
     * topic交换器你采用模糊匹配路由键的原则进行转发消息到队列中
     * key: queue在该direct-exchange中的key值，当消息发送给direct-exchange中指定key为设置值时，消息将会转发给queue参数指定
     * 的消息队列
     */
    private DirectExchange directExchange() {
        return new DirectExchange("hello", true, false);
    }

    /**
     * 定义rabbit template用于数据的接收和发送
     * 若使用confirm-callback或return-callback，必须要配置publisherConfirms或publisherReturns为true
     * 每个rabbitTemplate只能有一个confirm-callback和return-callback
     * 使用return-callback时必须设置mandatory为true，或者在配置中设置mandatory-expression的值为true，可针对每次请求的消息去确定’mandatory’的boolean值，
     * 只能在提供’return -callback’时使用，与mandatory互斥
     */
    @Bean
    public RabbitTemplate rabbitTemplate(CachingConnectionFactory cachingConnectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
        /*
         * 消息确认机制
         * Confirms给客户端一种轻量级的方式，能够跟踪哪些消息被broker处理，哪些可能因为broker宕掉或者网络失败的情况而重新发布。
         * 确认并且保证消息被送达，提供了两种方式：发布确认和事务。(两者不可同时使用)在channel为事务时，
         * 不可引入确认模式；同样channel为确认模式下，不可使用事务。
         */
        rabbitTemplate.setConfirmCallback(new MsgSendConfirmCallBack());
        return rabbitTemplate;
    }

    /**
     * @author Administrator
     */
    private class MsgSendConfirmCallBack implements RabbitTemplate.ConfirmCallback {
        @Override
        public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            System.out.println(" 回调id:" + correlationData);
            if (ack) {
                System.out.println("消息成功消费");
            } else {
                System.out.println("消息消费失败:" + cause + "\n重新发送");
            }
        }
    }

}